﻿using System;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace Ndns.Packet.ResourceRecords
{
    public sealed class DnsResourceRecordA : DnsResourceRecord
    {
        /// <summary>
        /// 表示应答中的A记录。
        /// </summary>
        public IPAddress Address { get; set; }
        public override DnsRecordType Type { get => DnsRecordType.A; set => throw new NotSupportedException(); }

        /// <summary>
        /// 根据相关信息构造DnsResourceRecordCNAME实例。
        /// </summary>
        /// <param name="hostName">DNS应答的主机名信息。</param>
        /// <param name="c">DNS应答的类别。</param>
        /// <param name="ttl">DNS应答的超时时间。</param>
        /// <param name="address">DNS应答的数据。</param>
        public DnsResourceRecordA(DnsHostName hostName, DnsClass c, uint ttl, IPAddress address)
            : base(hostName, c, ttl)
        {
            if (address == null)
                throw new ArgumentNullException(nameof(address));
            if (address.AddressFamily != AddressFamily.InterNetwork)
                throw new ArgumentOutOfRangeException(nameof(address));
            Address = address;
        }

        /// <summary>
        /// 从包含数据包的流中以支持指针的方式构造实例。
        /// </summary>
        /// <param name="packetStream">数据包流，Position应该指向要解析的应答的开始。</param>
        /// <param name="offset">数据包的开始位置在流中的偏移量。</param>
        /// <returns>解析得到的实例。</returns>
        public static new DnsResourceRecordA FromPacket(Stream packetStream, long packetStartIndex)
        {
            var hostName = DnsHostName.FromPacket(packetStream, packetStartIndex);
            var vType = packetStream.ReadNetworkUInt16();
            var vClass = packetStream.ReadNetworkUInt16();
            var vTTL = packetStream.ReadNetworkUInt32();
            PacketEndOfStreamException.CheckValue(vType, vClass);
            PacketEndOfStreamException.CheckValue(vTTL);
            int len = packetStream.ReadNetworkUInt16();
            if (len != 4)
                throw new FormatException();
            if ((DnsRecordType)vType != DnsRecordType.A)
                throw new FormatException();
            byte[] d = new byte[4];
            packetStream.Read(d);
            var vAnswer = new IPAddress(d);
            return new DnsResourceRecordA(hostName, (DnsClass)vClass, (uint)vTTL, vAnswer);
        }

        public override DnsResourceRecord Clone()
        {
            return new DnsResourceRecordA(HostName, Class, TTL, Address);
        }

        public override byte[] GetData()
        {
            if (Address == null || Address.AddressFamily != AddressFamily.InterNetwork)
                throw new FormatException();
            return Address.GetAddressBytes();
        }

        protected override int GetDataHashCode()
        {
            return Address.GetHashCode();
        }

        protected override bool TestDataEqualsTo(DnsResourceRecord other)
        {
            var record = other as DnsResourceRecordA;
            if (record == null)
                return false;
            return Address.Equals(record.Address);
        }
    }
}
